using System.Collections.Generic;
using FwkLight.Domain;

namespace FwkLight.CodeExtensions
{
  public interface IEnumerableActions<T>
  {
    void VisitAllItemsUsing ( IVisitor<T> visitor );
    TResult GetResultOfVisitingAllItemsWith<TResult> ( IValueReturningVisitor<TResult, T> visitor );
    IEnumerable<T> AllMatching ( ISpecification<T> specification );
    IEnumerable<TOutput> MapAllUsing<TOutput> ( IMapper<T, TOutput> mapper );
  }

	public interface IEnumerableActions<T, Param1>
	{
		IEnumerable<T> AllMatching(ISpecification<T, Param1> specification, Param1 param1);
	}

	public interface IEnumerableActions<T, Param1, Param2>
	{
		IEnumerable<T> AllMatching(ISpecification<T, Param1, Param2> specification, Param1 param1, Param2 param2);
	}

	public interface IEnumerableActions<T, Param1, Param2, Param3>
	{
		IEnumerable<T> AllMatching(ISpecification<T, Param1, Param2, Param3> specification, Param1 param1, Param2 param2, Param3 param3);
	}

	public interface IEnumerableActions<T, Param1, Param2, Param3, Param4>
	{
		IEnumerable<T> AllMatching(ISpecification<T, Param1, Param2, Param3, Param4> specification, Param1 param1, Param2 param2, Param3 param3, Param4 param4);
	}




  public class EnumerableActions<T> : IEnumerableActions<T>
  {
    private readonly IEnumerable<T> _itemsToActOn;


    public EnumerableActions ( IEnumerable<T> itemsToActOn )
    {
      _itemsToActOn = itemsToActOn;
    }

    public void VisitAllItemsUsing ( IVisitor<T> visitor )
    {
      foreach (T t in _itemsToActOn)
      {
        visitor.Visit(t);
      }
    }

    public TResult GetResultOfVisitingAllItemsWith<TResult> ( IValueReturningVisitor<TResult, T> visitor )
    {
      VisitAllItemsUsing(visitor);
      return visitor.GetResult();
    }

    public IEnumerable<T> AllMatching ( ISpecification<T> specification )
    {
      foreach (T t in _itemsToActOn)
      {
        if (specification.IsSatisfiedBy(t)) yield return t;
      }
    }

    public IEnumerable<TOutput> MapAllUsing<TOutput> ( IMapper<T, TOutput> mapper )
    {
      foreach (T t in _itemsToActOn)
      {
        yield return mapper.MapFrom(t);
      }
    }
  }

	public class EnumerableActions<T, Param1> : IEnumerableActions<T, Param1>
	{
		private readonly IEnumerable<T> _itemsToActOn;


		public EnumerableActions(IEnumerable<T> itemsToActOn)
		{
			_itemsToActOn = itemsToActOn;
		}

		public IEnumerable<T> AllMatching(ISpecification<T, Param1> specification, Param1 param1)
		{
			foreach (T t in _itemsToActOn)
			{
				if (specification.IsSatisfiedBy(t, param1)) yield return t;
			}
		}
	}

	public class EnumerableActions<T, Param1, Param2> : IEnumerableActions<T, Param1, Param2>
	{
		private readonly IEnumerable<T> _itemsToActOn;


		public EnumerableActions(IEnumerable<T> itemsToActOn)
		{
			_itemsToActOn = itemsToActOn;
		}

		public IEnumerable<T> AllMatching(ISpecification<T, Param1, Param2> specification, Param1 param1, Param2 param2)
		{
			foreach (T t in _itemsToActOn)
			{
				if (specification.IsSatisfiedBy(t, param1, param2)) yield return t;
			}
		}
	}

	public class EnumerableActions<T, Param1, Param2, Param3> : IEnumerableActions<T, Param1, Param2, Param3>
	{
		private readonly IEnumerable<T> _itemsToActOn;

		public EnumerableActions(IEnumerable<T> itemsToActOn)
		{
			_itemsToActOn = itemsToActOn;
		}

		public IEnumerable<T> AllMatching(ISpecification<T, Param1, Param2, Param3> specification, Param1 param1, Param2 param2, Param3 param3)
		{
			foreach (T t in _itemsToActOn)
			{
				if (specification.IsSatisfiedBy(t, param1, param2, param3)) yield return t;
			}
		}
	}

	public class EnumerableActions<T, Param1, Param2, Param3, Param4> : IEnumerableActions<T, Param1, Param2, Param3, Param4>
	{
		private readonly IEnumerable<T> _itemsToActOn;

		public EnumerableActions(IEnumerable<T> itemsToActOn)
		{
			_itemsToActOn = itemsToActOn;
		}

		public IEnumerable<T> AllMatching(ISpecification<T, Param1, Param2, Param3, Param4> specification, Param1 param1, Param2 param2, Param3 param3, Param4 param4)
		{
			foreach (T t in _itemsToActOn)
			{
				if (specification.IsSatisfiedBy(t, param1, param2, param3, param4)) yield return t;
			}
		}
	}
}